#include "stdafx.h"
#include "gmd_manager.h"
#include <stdio.h>
#include <stdlib.h>
using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

wchar_t* gmd_node::prefix_flag = L"-";

gmd_manager::gmd_manager(void)
{
}


gmd_manager::~gmd_manager(void)
{
}

void gmd_manager::decode_buffer(unsigned char* buf, int len, unsigned char mask)
{
	for ( int i = 0; i < len; i++ )
	{
		*(buf+i) = mask ^ (*(buf+i)&0xff);
	}
}

void gmd_manager::decode_string(wstring& wstr)
{
	int slen = wstr.length();
	if ( slen <= 0 )
		return;

	unsigned char tmp = ((slen*2)&0xff)^0xff;
	unsigned short wch[2] = {0};
	for ( int i = 0; i < slen; i++ )
	{
		wch[0] = tmp ^ (wstr[i]&0xff);
		wch[1] = tmp ^ ((wstr[i]>>8)&0xff);
		wstr[i] = (wch[1]<<8) | wch[0];
	}
}

bool gmd_manager::parse_gmd_file(const char* filename)
{
	bool retval = false;

	FILE* pf = NULL;
	fopen_s(&pf, filename, "rb");
	if ( pf == NULL )
		return retval;

	size_t filesize, readsize;
	fseek(pf, 0, SEEK_END);
	filesize = (size_t)ftell(pf);
	fseek(pf, 0, SEEK_SET);

	char* data = new char[filesize];

	CString strLine;
	strLine.Format(_T("-----------------------------%S----------------------------\n"), filename);

	OutputDebugString( strLine );

	readsize = fread(data, 1, filesize, pf);
	if ( readsize == readsize )
	{
		try
		{
			parse_gmd_filebuffer(data, filesize );
		}
		catch(...)
		{
		}
	}
	OutputDebugString( _T("-------------------------------------------------------------------------\n") );

	delete[] data;

	fclose(pf);
	return true;
}

size_t gmd_manager::parse_gmd_file(const char* buffer, size_t size, gmd_node* node)
{
	vector<char> strbuf;
	strbuf.resize(32);

	TPack pack(TPack::OP_UNPACK);
	pack.copydata(buffer, size);

	pack.serial(node->version);
	if ( node->version == 0x01014154 )
	{
		unsigned int old_value = 0;
		pack.serial(old_value);
		node->count = old_value;
	}
	else
	{
		pack.serial(node->count);
	}
	node->children = gmd_node::new_children(node->count);

	for ( unsigned short i = 0; i < node->count; i++ )
	{
		pack.serial(node->children[i].type);

		if ( node->version == 0x01014154 )
		{
			node->children[i].name = L"unnamed_node";
			node->children[i].prefix = node->prefix + gmd_node::prefix_flag;
		}
		else
		{
			unsigned short len = 0;
			pack.serial( len );
			if ( len > strbuf.size() )
				strbuf.resize( len );
		
			pack.serial( strbuf.data(), len );

			node->children[i].prefix = node->prefix + gmd_node::prefix_flag;
			node->children[i].name.assign( (wchar_t*)strbuf.data(), len/2 );

			decode_string( node->children[i].name );
		}

		switch ( node->children[i].type )
		{
		case 0x0b:
		case 0x0c:
			{
				unsigned int cb = 0;
				pack.serial( cb );

				parse_gmd_file( buffer+pack.offset(), cb, &(node->children[i]) );
				pack.seek(pack.offset()+cb);
			}
			break;
		case 0x01:
		case 0x02:
		case 0x06:
		case 0x07:
		case 0x09:
			{
				unsigned int cb = 0;
				pack.serial( cb );
				node->children[i].values.resize(cb);

				bool decode = (cb > 4)?true:false;
				unsigned char mask = (cb&0xff)^0xff;
				for ( unsigned int j = 0; j < cb; j++ )
				{
					pack.serial(node->children[i].values[j]);
					if ( decode )
						decode_buffer(&node->children[i].values[j], sizeof(unsigned char), mask);
				}
			}
			break;
		case 0x08:
			{
				pack.serial<unsigned int>(node->children[i].strval);
				decode_string( node->children[i].strval );
			}
			break;
		default:
			break;
		}
	}
	
	return 0;
}

int gmd_manager::parse_gmd_filebuffer(const char* buffer, size_t size)
{
	int retval = 0;

	gmd_node node;
	parse_gmd_file(buffer, size, &node );

	trace_gmd_nodes( &node );

	return retval;
}

void gmd_manager::trace_gmd_nodes(gmd_node* node)
{
	CString strLine;

	for ( unsigned short i = 0; i < node->count; i++ )
	{
		strLine.Empty();
		switch( node->children[i].type )
		{
		case 0x0c:
		case 0x0b:
			{
				strLine.Format( _T("%s%s\n"), node->children[i].prefix.c_str(), node->children[i].name.c_str());
				OutputDebugString( strLine );
				if ( node->children !=  NULL )
				{
					trace_gmd_nodes( &node->children[i] );
				}
			}
			break;
		case 0x08:
			{
				strLine.Format( _T("%s%s: %s\n"), node->children[i].prefix.c_str(), node->children[i].name.c_str(), node->children[i].strval.c_str());
				OutputDebugString( strLine );
			}
			break;
		case 0x01:
		case 0x02:
		case 0x06:
		case 0x07:
		case 0x09:
			{
				CString strTemp, strVal;
				unsigned int count = node->children[i].values.size();
				for ( unsigned int j = 0; j < count; j++ )
				{
					strVal.Format(_T(" %u"), node->children[i].values[j]);
					strTemp += strVal;
				}

				strLine.Format( _T("%s%s: %s\n"), node->children[i].prefix.c_str(), node->children[i].name.c_str(), strTemp);
				OutputDebugString( strLine );
			}
			break;
		default:
			break;
		}
	}
}

